﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.ServiceLocation;
using Pap.Core.Utilities;
using Pap.Data;
using Pap.Data.Abstraction.Utils;
using Pap.Services;
using Pap.Services.WorkflowEngine;
using Pap.Web.Utils;
using Utils;

namespace Pap.Web.Modules.Loan.ViewModel
{
    /// <summary>
    /// 
    /// </summary>
    public class ReviewerWaitingListViewModel : IViewModel
    {
        /// <summary>
        /// 
        /// </summary>
        ILoanRepository _LoanRepository;
        /// <summary>
        /// 
        /// </summary>
        IWorkflowService _WorkflowService;
        /// <summary>
        /// 
        /// </summary>
        IAdministrationRepository _AdministrationRepository;

        /// <summary>
        /// Initializes a new instance of the <see cref="ReviewerWaitingListViewModel"/> class.
        /// </summary>
        /// <param name="loanRepository">The loan repository.</param>
        /// <param name="workflowService">The workflow service.</param>
        /// <param name="AdminRepository">The admin repository.</param>
        public ReviewerWaitingListViewModel(ILoanRepository loanRepository, IWorkflowService workflowService, IAdministrationRepository AdminRepository)
        {
            _LoanRepository = loanRepository;
            _WorkflowService = workflowService;
            _AdministrationRepository = AdminRepository;
        }

        /// <summary>
        /// Gets the waiting boards.
        /// </summary>
        /// <returns></returns>
        public IEnumerable GetWaitingBoards()
        {
            IEnumerable<IProject> userProjects = _AdministrationRepository.GetUserProjects(RegistryInfo.UserID);
            var boardsIds = _WorkflowService.GetInStep(Steps.BoardReviewList);
            return (from board in _LoanRepository.FindBoard(b => boardsIds.Contains(b.BoardID))
                    where board.BoardLoans != null && userProjects.Contains(board.BoardLoans.First().LoanObj.ProjectStage.ProjectObj)
                    orderby board.BoardNumber ascending
                    select new
                    {
                        BoardID = board.BoardID,
                        BoardNumber = board.BoardNumber,
                        CommitteeName = board.CommitteeObj.CommitteeName,
                        ExpertName = _WorkflowService.GetStep(_WorkflowService.GetProcessInstanceIDByEntity(board.BoardID)).User.DisplayName,
                        BoardDate = board.BoardDate,
                        BoardStatus = _WorkflowService.GetStep(_WorkflowService.GetProcessInstanceIDByEntity(board.BoardID)).DisplayName.ToString(),
                        PreviousNotes = _WorkflowService.GetStep(_WorkflowService.GetProcessInstanceIDByEntity(board.BoardID)).PreviousNotes,
                    });
        }

        /// <summary>
        /// Gets the available actions.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<ActionTypes> GetAvailableActions()
        {
            return _WorkflowService.GetAvailableActionsByStep(Steps.ReviewList);
        }

        /// <summary>
        /// Gets the board loans.
        /// </summary>
        /// <param name="boardID">The board ID.</param>
        /// <returns></returns>
        public IEnumerable GetBoardLoans(Guid boardID)
        {
            var reviewerLoansIDs = _WorkflowService.GetInStep(Steps.ReviewList);

            var result = (from boardLoan in _LoanRepository.FindBoardLoans(bl => bl.BoardID == boardID)
                          where reviewerLoansIDs.Contains(boardLoan.LoanID)
                          orderby boardLoan.LoanObj.LoanNumber ascending
                          let loanStep = _WorkflowService.GetStep(_WorkflowService.GetProcessInstanceIDByEntity(boardLoan.LoanID))
                          select new
                          {
                              LoanID = boardLoan.LoanID,
                              LoanNumber = boardLoan.LoanObj.LoanNumber,
                              LoanCreatedDate = boardLoan.LoanObj.LoanCreatedDate,
                              CustomerName = boardLoan.LoanObj.CustomerObj.CustomerName,
                              LoanType = boardLoan.LoanObj.LoanTypeObj.Name,
                              BoardLoanAmount = boardLoan.BoardLoanAmount,
                              BoardPaymentPeriod = boardLoan.BoardPaymentPeriod,
                              BoardDecision = loanStep.DisplayName.ToString(),
                              PreviousNotes = loanStep.PreviousNotes,
                              DecisionID = Enums.ToString(loanStep.ActionType),
                              Editable = Enums.ToString(loanStep.ActionType).ToGuid().Equals(
                              Enums.ToString(ActionTypes.Accept).ToGuid()),
                              ActionTypeID = Enums.ToString(loanStep.ActionType)
                          });

            return result;
        }

        /// <summary>
        /// Gets the board attachements.
        /// </summary>
        /// <param name="boardID">The board ID.</param>
        /// <returns></returns>
        public IEnumerable<IImage> GetBoardAttachements(Guid boardID)
        {
            return _LoanRepository.GetBoardByID(boardID).BoardAttachments.Select(att => att.AttachmentImage);
        }

        /// <summary>
        /// Submits the board.
        /// </summary>
        /// <param name="boardID">The board ID.</param>
        /// <param name="notes">The notes.</param>
        /// <param name="loansIds">The loans ids.</param>
        /// <param name="loansNotes">The loans notes.</param>
        /// <param name="loansDecisions">The loans decisions.</param>
        public void SubmitBoard(Guid boardID, string notes, List<Guid> loansIds, List<string> loansNotes, List<Pap.Services.WorkflowEngine.ActionTypes> loansDecisions)
        {
            using (IUnitOfWork trancaction = ServiceLocator.Current.GetInstance<IUnitOfWork>())
            {
                Guid processInstanceID;
                for (int i = 0; i < loansIds.Count; i++)
                {
                    processInstanceID = _WorkflowService.GetProcessInstanceIDByEntity(loansIds[i]);
                    var step = _WorkflowService.GetStep(processInstanceID);

                    Guid decisionID = Enums.ToString(loansDecisions[i]).ToGuid();
                    if (decisionID.Equals(Enums.ToString(ActionTypes.FreezWithoutResearchAndStudy).ToGuid()) ||
                        decisionID.Equals(Enums.ToString(ActionTypes.FreezWithResearchAndStudy).ToGuid()))
                        _WorkflowService.Move(loansDecisions[i], processInstanceID, RegistryInfo.UserID, loansNotes[i], step.CompletionDate);
                    else
                        _WorkflowService.Move(loansDecisions[i], processInstanceID, RegistryInfo.UserID, loansNotes[i], null);
                }

                processInstanceID = _WorkflowService.GetProcessInstanceIDByEntity(boardID);
                _WorkflowService.Move(ActionTypes.Submit, processInstanceID, RegistryInfo.UserID, notes, null);

                trancaction.Commit();
            }
        }

        /// <summary>
        /// Returns the board.
        /// </summary>
        /// <param name="boardID">The board ID.</param>
        /// <param name="notes">The notes.</param>
        public void ReturnBoard(Guid boardID, string notes)
        {
            using (IUnitOfWork trancaction = ServiceLocator.Current.GetInstance<IUnitOfWork>())
            {
                var reviewLoans = _WorkflowService.GetInStep(Steps.ReviewList);
                IBoard returnBoard = _LoanRepository.GetBoardByID(boardID);
                var returnedloans = returnBoard.BoardLoans.Where(loan => reviewLoans.Contains(loan.LoanID));
                returnedloans.ForEach(returnlaon =>
                    {
                        Guid loanProcessInstanceID = _WorkflowService.GetProcessInstanceIDByEntity(returnlaon.LoanID);
                        _WorkflowService.Move(ActionTypes.Return, loanProcessInstanceID, RegistryInfo.UserID, string.Empty, null);
                    });


                Guid processInstanceID = _WorkflowService.GetProcessInstanceIDByEntity(boardID);
                _WorkflowService.Move(ActionTypes.Return, processInstanceID, RegistryInfo.UserID, notes, null);

                trancaction.Commit();
            }
        }
    }
}
